//#include <dirent.h>
//#include <cstdlib>
#include "NWayMerge.h"


NWayMerge::NWayMerge(char* rutaRepo){
    rutaRepositorio = (char*) new char[ANCHO_DIRECTORIO_ARCH_IDX_REPO+1];
    strcpy(this->rutaRepositorio,rutaRepo);
    cantTerminosDistintos = 0;
    cantArchAMergear = 0;
    cantConj = 0;
}

NWayMerge::NWayMerge() {
    rutaRepositorio = (char*) new char[ANCHO_DIRECTORIO_ARCH_IDX_REPO+1];
    raizDeCantArchRepositorio = 0;
    cantTerminosDistintos = 0;
    cantArchAMergear = 0;
    cantConj = 0;
}

NWayMerge::NWayMerge(const NWayMerge& orig) {
}

NWayMerge::~NWayMerge() {
    delete[] rutaRepositorio;
    /*La siguiente validacion es para que no intente abrir la carpeta "CARPETA_PARTICIONES_MERGE"
     * para borrar su contenido si no fue creada por no tener archivos para mergear*/
    if(cantArchAMergear > 0)
    	this->removeContenidoCarpetaSalidas();
}

void NWayMerge::crearArchFinalDelNWayMerge(std::fstream*& fdMatrizInicial){
    
    char rutaRepo[ANCHO_DIRECTORIO_ARCH_IDX_REPO];
    std::string nombreConcatenadoConRutaArch;
    
    strcpy(rutaRepo,LSI_DIRECTORY);
    nombreConcatenadoConRutaArch = strcat(rutaRepo,NOMBRE_ARCH_MAT_INICIAL);
    fdMatrizInicial = new std::fstream(nombreConcatenadoConRutaArch.c_str(),std::ios::out);

    // guardo al principio del archivo un 0 como unsigned long int al principio del archivo para despues mas tarde guardar la cantidad de terminos distintos
    fdMatrizInicial->write("0",sizeof(unsigned long int) );
}

unsigned int NWayMerge::contarCantArchivosAMergear(){

    struct dirent *entry;
    DIR* directorio = opendir(this->rutaRepositorio);
    unsigned int cantArchivosDir = 0;
    
    if(directorio == NULL)
    	std::cerr << "[ERROR-APERTURA-DIR-ARCHIVOS-A-MERGEAR]: No se pudo abrir el directorio \"" << this->rutaRepositorio << "\" para contar" << std::endl;
    else{
		while((entry = readdir(directorio))){
			if( (strcmp(entry->d_name,".")!= 0) && (strcmp(entry->d_name,"..") != 0) && (strstr(entry->d_name,"~") == NULL))
				if(strstr(entry->d_name,IDENTIFICADOR_ARCHS_A_MERGEAR)!= NULL )
					cantArchivosDir++;
		}
		closedir(directorio);
		this->cantArchAMergear = cantArchivosDir;
    }
    return cantArchivosDir;
}

/*TODO ver que ande*/
unsigned int NWayMerge::obtenerCantTerminosMinimo(registroMatrizInicial**  vecDeRegistrosAMergear) const{

    unsigned int posMin,i,j;
    unsigned char cantTermMinimo = 0;

    //Lo siguiente es para que el minimo no sea NULL;
    //Pues si termina de leer un archivo puede apuntar a NULL y tratar de obtener el término
    i=0;
    do{
        posMin = i;
        i++;
    }while( (vecDeRegistrosAMergear[posMin]== NULL) && (i <= (this->raizDeCantArchRepositorio-1) ) );

    //busco la posicion del minimo
    for(i=0;i<(this->raizDeCantArchRepositorio-1);i++){
        j=i+1;
        if(vecDeRegistrosAMergear[j]!= NULL){
            if( (vecDeRegistrosAMergear[posMin])->getTermino()  > (vecDeRegistrosAMergear[j])->getTermino() ){
                posMin = j;//nuevo minimo
                cantTermMinimo = 1;
            }else{
                if( (vecDeRegistrosAMergear[posMin])->getTermino() == (vecDeRegistrosAMergear[j])->getTermino() ){//mismo término
                	++cantTermMinimo;
                    //el minimo será el de menor ArchID
                    if(vecDeRegistrosAMergear[posMin]->getNroDocumento() > vecDeRegistrosAMergear[j]->getNroDocumento())
                        posMin = j;
                }
            }
        }
    }
    return cantTermMinimo;
}

/*TODO ver que ande*/
int comparaPosiciones(const void* pos1,const void* pos2){

	if( *(unsigned int*)pos1 < *(unsigned int*)pos2 )
		return -1;
	if( *(unsigned int*)pos1 == *(unsigned int*)pos2 )
		return 0;
	else
		return 1;
	//if( *(unsigned int*)pos1 > *(unsigned int*)pos2 ) return 1;
}

/*TODO ver que ande*/
void NWayMerge::obtengoPosicionesOrdenadasTermMinEnVecReg(unsigned int cantTerminosMin,unsigned int*& vecTempPosTermMin,registroMatrizInicial**  vecDeRegistrosAMergear){

    unsigned int posMin,i,j,posEnVecTempPosTermMin = 0;

    //Lo siguiente es para que el minimo no sea NULL;
    //Pues si termina de leer un archivo puede apuntar a NULL y tratar de obtener el término
    i=0;
    do{
        posMin = i;
        i++;
    }while( (vecDeRegistrosAMergear[posMin]== NULL) && (i <= (this->raizDeCantArchRepositorio-1) ) );

    //busco la posicion del minimo
    for(i=0;i<(this->raizDeCantArchRepositorio-1);i++){
        j=i+1;
        if(vecDeRegistrosAMergear[j]!= NULL){
            if( (vecDeRegistrosAMergear[posMin])->getTermino()  > (vecDeRegistrosAMergear[j])->getTermino() ){
                posMin = j;//nuevo minimo
                posEnVecTempPosTermMin = 0;
            }else{
                if( (vecDeRegistrosAMergear[posMin])->getTermino() == (vecDeRegistrosAMergear[j])->getTermino() ){//mismo término
                	//Ordeno el vecTempPosTermMin una vez obtenido todas las posiciones
                	vecTempPosTermMin[posEnVecTempPosTermMin] = j;
                	posEnVecTempPosTermMin++;
                    //el minimo será el de menor ArchID
                    if(vecDeRegistrosAMergear[posMin]->getNroDocumento() > vecDeRegistrosAMergear[j]->getNroDocumento())
                        posMin = j;
                }
            }
        }
    }
    //ordeno el vector de punteros para que primero este el de < ID doc al >.
    qsort(vecTempPosTermMin,cantTerminosMin,sizeof(unsigned int),comparaPosiciones);
}

unsigned int NWayMerge::obtengoPosicionTermMin(registroMatrizInicial**  vecDeRegistrosAMergear) const{
    
    unsigned int posMin,i,j;
    //Lo siguiente es para que el minimo no sea NULL;
    //Pues si termina de leer un archivo puede apuntar a NULL y tratar de obtener el término
    for (i=0; i<this->raizDeCantArchRepositorio; i++) {
    	posMin = i;
    	if (vecDeRegistrosAMergear[posMin]!= NULL) break;
    }
    //busco la posicion del minimo
    for(i=posMin;i<(this->raizDeCantArchRepositorio)-1;i++){
        j=i+1;
        if(vecDeRegistrosAMergear[j]!= NULL){
            if( vecDeRegistrosAMergear[posMin]->getTermino() > (vecDeRegistrosAMergear[j])->getTermino() ){
            	posMin = j;//nuevo minimo
            }else{
                if( (vecDeRegistrosAMergear[posMin])->getTermino() == (vecDeRegistrosAMergear[j])->getTermino() ){//mismo término
                    //el minimo será el de menor ArchID
                    if(vecDeRegistrosAMergear[posMin]->getNroDocumento() > vecDeRegistrosAMergear[j]->getNroDocumento())
                    	posMin = j;
                }
            }
        }
    }
    return posMin;
}

unsigned int NWayMerge::fase2obtengoPosicionTermMin(registroMatrizInicial**  vecDeRegistrosAMergear) const{

    unsigned int posMin,i,j;

    //Lo siguiente es para que el minimo no sea NULL;
    //Pues si termina de leer un archivo puede apuntar a NULL y tratar de obtener el término
    for (i=0; i<this->cantConj; i++) {
    	posMin = i;
    	if (vecDeRegistrosAMergear[posMin]!= NULL) break;
    }

    //busco la posicion del minimo
    for(i=posMin;i<(this->cantConj);i++){
        j=i+1;
        if(j < this->cantConj){
			if(vecDeRegistrosAMergear[j]!= NULL){
				if( vecDeRegistrosAMergear[posMin]->getTermino() > (vecDeRegistrosAMergear[j])->getTermino() ){
					posMin = j;//nuevo minimo
				}else{
					if( (vecDeRegistrosAMergear[posMin])->getTermino() == (vecDeRegistrosAMergear[j])->getTermino() ){//mismo término
						//el minimo será el de menor ArchID
						if(vecDeRegistrosAMergear[posMin]->getNroDocumento() > vecDeRegistrosAMergear[j]->getNroDocumento())
							posMin = j;
					}
				}
			}
		}
    }
    return posMin;
}

void NWayMerge::fase1InicializarVectores(registroMatrizInicial**& vectorDeRegistrosEntrada,std::fstream*& vecArchsEntrada,
                                    std::fstream**& vecArchsSalida){

    vectorDeRegistrosEntrada = new (std::nothrow) registroMatrizInicial*[this->raizDeCantArchRepositorio];
    if(vectorDeRegistrosEntrada == NULL)
        std::cerr << "[ERROR-MEMORIA_DINAMICA]: No se pudo asignar suficiente memoria para \"vectorDeRegistrosEntreada\" ."<<std::endl;
    vecArchsEntrada = new (std::nothrow) std::fstream[this->raizDeCantArchRepositorio];
    if(vecArchsEntrada == NULL)
        std::cerr << "[ERROR-MEMORIA_DINAMICA]: No se pudo asignar suficiente memoria para \"vecArchsEntreada\" ."<<std::endl;
    vecArchsSalida = new (std::nothrow) std::fstream*[this->cantConj];
    if(vecArchsSalida == NULL)
        std::cerr << "[ERROR-MEMORIA_DINAMICA]: No se pudo asignar suficiente memoria para \"vecArchsSalida\" ."<<std::endl;    
}

void NWayMerge::fase2inicializarVectores(const unsigned int& cantConj,registroMatrizInicial**& vectorDeRegistrosEntrada,std::fstream*& vecArchsEntrada){
    
    vectorDeRegistrosEntrada = new (std::nothrow) registroMatrizInicial*[cantConj];
    if(vectorDeRegistrosEntrada == NULL)
        std::cerr << "[ERROR-MEMORIA_DINAMICA]: No se pudo asignar suficiente memoria para \"vectorDeRegistrosEntrada\" ."<<std::endl;
    vecArchsEntrada = new (std::nothrow) std::fstream[cantConj];
    if(vecArchsEntrada == NULL)
        std::cerr << "[ERROR-MEMORIA_DINAMICA]: No se pudo asignar suficiente memoria para \"vecArchsEntrada\" ."<<std::endl;

}

/*
void NWayMerge::contabilizarTerminosDistintos(std::fstream*& fdArchTermDistintos,std::string& terminoMinimoAnterior,registroMatrizInicial** vectorDeRegistrosEntrada, unsigned int& posMinimo){
    
    if(terminoMinimoAnterior.compare(vectorDeRegistrosEntrada[posMinimo]->getTermino() )){        
        terminoMinimoAnterior = vectorDeRegistrosEntrada[posMinimo]->getTermino();
        (this->cantTerminosDistintos)++;
        this->persistirTerminoDistinto(*fdArchTermDistintos,this->cantTerminosDistintos,terminoMinimoAnterior);
    }
}
*/

void NWayMerge::contabilizarTerminosDistintos(std::string& terminoMinimoAnterior, std::string terminoActual) {

    if(terminoMinimoAnterior.compare(terminoActual )){
        terminoMinimoAnterior = terminoActual;
        (this->cantTerminosDistintos)++;
    }
}

void NWayMerge::persisitirCantTerminosDistintos(){
        
    char rutaArchivoAEscribir[ANCHO_DIRECTORIO_ARCH_IDX_REPO]= LSI_DIRECTORY;
    char nombreArch[ANCHO_NOMBRE_REPO] = NOMBRE_ARCH_CANT_TERMINOS_DISTINTOS;
    std::string indexadorCantTermino = INDEXER_CANT_TERM;
    std::fstream* fdDatosNuestros;
    
    
    strcat(rutaArchivoAEscribir,nombreArch);
    fdDatosNuestros = new std::fstream(rutaArchivoAEscribir,std::ios_base::binary |std::ios_base::out | std::ios_base::app);
    if(fdDatosNuestros != NULL){
        if(!fdDatosNuestros->is_open())
            fdDatosNuestros->open(rutaArchivoAEscribir,std::ios_base::binary | std::ios_base::app);
        if(fdDatosNuestros->fail())
            std::cerr<<"[ERROR][APERTURA-DATOS.DAT]: No se pudo abrir el archivo."<<std::endl;
        fdDatosNuestros->write(indexadorCantTermino.c_str(),indexadorCantTermino.length());
        if(fdDatosNuestros->fail())
            std::cerr<<"[ERROR][ESCRITURA-DATOS.DAT]: No se pudo escribir: ("<<indexadorCantTermino<<") en el archivo."<<std::endl;
        fdDatosNuestros->write( (char*)&(this->cantTerminosDistintos),sizeof(unsigned long int));
        if(fdDatosNuestros->fail())
            std::cerr<<"[ERROR][ESCRITURA-DATOS.DAT]: No se pudo escribir: CANT_TERMINOS_DISTINTOS ("<<this->cantTerminosDistintos<<") en el archivo."<<std::endl;
        fdDatosNuestros->close();
    }
    else
        std::cerr<<"[ERROR][VINCULACION-DATOS:DAT]"<<std::endl;
    delete fdDatosNuestros;
}

void NWayMerge::creoArchConTodosLosTermDistintos(std::fstream*& fdArchTermDistintos){
    
    char rutaArchivoAEscribir[ANCHO_DIRECTORIO_ARCH_IDX_REPO]= LSI_DIRECTORY;
    char nombreArch[ANCHO_NOMBRE_REPO] = NOMBRE_ARCH_TERM_DISTINTOS;
    
    strcat(rutaArchivoAEscribir,nombreArch);
    fdArchTermDistintos = new std::fstream(rutaArchivoAEscribir,std::ios_base::binary | std::ios_base::out);
    if(fdArchTermDistintos != NULL){
        if(!fdArchTermDistintos->is_open())
            fdArchTermDistintos->open(rutaArchivoAEscribir,std::ios_base::binary | std::ios_base::out);
    }else{
        std::cerr<<"[ERROR][CREACION-ARCH_TERM_DISTINTOS]"<<std::endl;
    }
}

void NWayMerge::cierroYLiberoArchTermDistintos(std::fstream*& fdArchTermDistintos){
    
    if(fdArchTermDistintos->is_open())
        fdArchTermDistintos->close();
    delete fdArchTermDistintos;
}

void NWayMerge::persistirTerminoDistinto(std::fstream& fd,unsigned long int j,std::string& terminoAPersistir){
        
    fd.write(reinterpret_cast<char*>(&j),sizeof(unsigned long int) );
    if(fd.fail())
        std::cerr<<"[ERROR][PERSISTIR-TERMINO-indice]: ("<<j<<")."<<std::endl;    
    fd.write(terminoAPersistir.c_str(),ANCHO_TERMINOS_DISTINTOS);
    if(fd.fail())
        std::cerr<<"[ERROR][PERSISTIR-TERMINO]: ("<<terminoAPersistir<<")."<<std::endl;
}

unsigned int NWayMerge::round(float x){
    return static_cast<int>(floor(x + 0.5f));
}

void NWayMerge::fase1crearParticionesDeSalida(unsigned int cantConj,std::fstream**& vecArchsSalida){

    unsigned int j;
    char representacionDeJ;
    std::string rutaConNombreParticionesMerge(CARPETA_PARTICIONES_MERGE);

	for(j= 0;j<cantConj;j++){
		itoa(j,&representacionDeJ);
		rutaConNombreParticionesMerge.append(&representacionDeJ);
		rutaConNombreParticionesMerge.append(NOMBRE_PARTICIONES_SALIDA_MERGE);
		vecArchsSalida[j] = new (std::nothrow)std::fstream(rutaConNombreParticionesMerge.c_str(),std::ios::binary | std::ios::out);
		if(vecArchsSalida[j]->fail())
			std::cerr << "fallo vecArchSalida[j] = new ..."<<std::endl;
		else{// Si pudo crearlos los abro para escritura.
			vecArchsSalida[j]->close();
			vecArchsSalida[j]->open(rutaConNombreParticionesMerge.c_str(),std::ios::binary | std::ios::in | std::ios::out);
			if(vecArchsSalida[j]->fail())
				std::cerr << "[ERROR]: No se pudo abrir los archivos: \"" << NOMBRE_PARTICIONES_SALIDA_MERGE << "\"" <<std::endl;
		}
		rutaConNombreParticionesMerge.assign("");
		rutaConNombreParticionesMerge.assign(CARPETA_PARTICIONES_MERGE);
	}
}

void NWayMerge::fase1PosicionarSoloSobreArchsAMergear(struct dirent*& entry,DIR*& ruta){

	while( strstr(entry->d_name,IDENTIFICADOR_ARCHS_A_MERGEAR) == NULL )
		entry = readdir(ruta);
}

/* OK */
void NWayMerge::fase1cargarPosicionesTermino(unsigned int j,unsigned int repeticionesLeidas,unsigned int*& vecPosTerm,const char* nombreArch,
											std::fstream*& vecArchsEntrada){

	unsigned int i = 0;

	do{
		vecArchsEntrada[j].read(reinterpret_cast<char*>(&vecPosTerm[i]),sizeof(int));
		if(vecArchsEntrada[j].fail())
			std::cerr << "[ERROR][FASE-1][CARGA_POSICIONES]:Lectura parametro: POSICION("<<i<<") de archivo \""<<nombreArch<<"\". " << std::endl;
		vecArchsEntrada[j].clear();
		i++;
	}while(i < repeticionesLeidas);
}

/* OK */
void NWayMerge::fase1cargarVecRegsEntrada(unsigned int j,struct dirent* entry,std::fstream*& vecArchsEntrada,registroMatrizInicial**& vectorDeRegistrosEntrada){

    unsigned char largoTermino = 0;
    char termino[LONG_TERMINO] = "";
    std::string strTermino;
    unsigned int nroDocLeido,repeticionesLeidas;
    unsigned int* vecPosTerm = NULL;

	vecArchsEntrada[j].read(reinterpret_cast<char*>(&nroDocLeido),sizeof(int) );
	if(vecArchsEntrada[j].fail())
		std::cerr << "[ERROR][FASE-1]:Lectura parametro: NRO_DOC("<<nroDocLeido<<") de archivo \""<<entry->d_name<<"\". " << std::endl;
	vecArchsEntrada[j].clear();
	vecArchsEntrada[j].read(reinterpret_cast<char*>(&largoTermino),sizeof(char));
	if(vecArchsEntrada[j].fail())
		std::cerr << "[ERROR][FASE-1]:Lectura parametro: LARGO_TERMINO("<<largoTermino<<") desde archivo \""<<entry->d_name<<"\". " << std::endl;
	vecArchsEntrada[j].clear();
	vecArchsEntrada[j].read(termino,largoTermino*sizeof(char));
	if(vecArchsEntrada[j].fail())
		std::cerr << "[ERROR][FASE-1]:Lectura parametro: TERMINO("<<termino<<") de archivo \""<<entry->d_name<<"\". " << std::endl;
	termino[largoTermino] = '\0'; //por las dudas hubo uno que vino sin el '\0' .
	vecArchsEntrada[j].clear();
	vecArchsEntrada[j].read(reinterpret_cast<char*>(&repeticionesLeidas),sizeof(int));
	if(vecArchsEntrada[j].fail())
		std::cerr << "[ERROR][FASE-1]:Lectura parametro: REPETICIONES("<<repeticionesLeidas<<") de archivo \""<<entry->d_name<<"\". " << std::endl;
	vecArchsEntrada[j].clear();
	strTermino.assign(termino,largoTermino);
	//Leo cada posicion y lo almazeno en un vector de posiciones.
	vecPosTerm = new unsigned int[repeticionesLeidas];
	this->fase1cargarPosicionesTermino(j,repeticionesLeidas,vecPosTerm,entry->d_name,vecArchsEntrada);
	vectorDeRegistrosEntrada[j] = new registroMatrizInicial(nroDocLeido,repeticionesLeidas,strTermino,vecPosTerm);//constructor de copia
	delete [] vecPosTerm;
}

/* OK */
void NWayMerge::fase1persistirPosicionesTerminoEnArchQueCree(unsigned int cantConjProcesados,unsigned int repeticionesLeidas, unsigned int* vecPosTerm,
															std::fstream**& vecArchsSalida){

	unsigned int i;

	for( i = 0; i < repeticionesLeidas; i++){
		vecArchsSalida[cantConjProcesados]->write(reinterpret_cast<char*>(&vecPosTerm[i]),sizeof(int));
		if(vecArchsSalida[cantConjProcesados]->fail())
			std::cerr<<"[ERROR][MERGE-FASE1-ESCRITURA]: parametro POSICION["<<i<<"] en el archivo \"" << cantConjProcesados << NOMBRE_PARTICIONES_SALIDA_MERGE << std::endl;
		vecArchsSalida[cantConjProcesados]->clear();
	}
}

/* OK */
void NWayMerge::fase1EscribirMenorEnLaParticionDeSalida(unsigned int posMinimo,unsigned int cantConjProcesados,registroMatrizInicial**& vectorDeRegistrosEntrada,
														std::fstream**& vecArchsSalida){

    unsigned char largoTermino = 0;
    unsigned int nroDocLeido,repeticionesLeidas;
    unsigned int* vecPosTermMinimo = NULL;

	//Escribo el nro doc;
	nroDocLeido = vectorDeRegistrosEntrada[posMinimo]->getNroDocumento();
	vecArchsSalida[cantConjProcesados]->write(reinterpret_cast<char*>(&nroDocLeido),sizeof(int));
	if(vecArchsSalida[cantConjProcesados]->fail())
		std::cerr<<"[ERROR][MERGE-FASE1-ESCRITURA]: parametro NRO_DOC("<<nroDocLeido<<") en archivo \""<<cantConjProcesados << NOMBRE_PARTICIONES_SALIDA_MERGE <<std::endl;
	vecArchsSalida[cantConjProcesados]->clear();
    largoTermino = vectorDeRegistrosEntrada[posMinimo]->getTermino().length();
	//Escribo la longitud del minimo;
	vecArchsSalida[cantConjProcesados]->write((char*)&largoTermino,sizeof(char));
	if(vecArchsSalida[cantConjProcesados]->fail())
		std::cerr<<"[ERROR][MERGE-FASE1-ESCRITURA]: parametro LARGO_TERMINO("<<largoTermino<<") en archivo \""<<cantConjProcesados << NOMBRE_PARTICIONES_SALIDA_MERGE <<std::endl;
	vecArchsSalida[cantConjProcesados]->clear();
	//Escribo el menor termino;
	vecArchsSalida[cantConjProcesados]->write(vectorDeRegistrosEntrada[posMinimo]->getTermino().c_str(),vectorDeRegistrosEntrada[posMinimo]->getTermino().length()*sizeof(char));
	if(vecArchsSalida[cantConjProcesados]->fail())
		std::cerr<<"[ERROR][MERGE-FASE1-ESCRITURA]: parametro TERMINO("<<vectorDeRegistrosEntrada[posMinimo]->getTermino().c_str()<<") en archivo \""<<cantConjProcesados << NOMBRE_PARTICIONES_SALIDA_MERGE <<std::endl;
	vecArchsSalida[cantConjProcesados]->clear();
	//Escribo frecuencia del termino;
	repeticionesLeidas = vectorDeRegistrosEntrada[posMinimo]->getFrecuencia();
	vecArchsSalida[cantConjProcesados]->write(reinterpret_cast<char*>(&repeticionesLeidas),sizeof(int));
	if(vecArchsSalida[cantConjProcesados]->fail())
		std::cerr<<"[ERROR][MERGE-FASE1-ESCRITURA]: parametro REPETICIONES("<<repeticionesLeidas<<") en archivo \""<<cantConjProcesados << NOMBRE_PARTICIONES_SALIDA_MERGE <<std::endl;
	vecArchsSalida[cantConjProcesados]->clear();
	//Escribo posiciones del termino
	this->fase1persistirPosicionesTerminoEnArchQueCree(cantConjProcesados,repeticionesLeidas,vectorDeRegistrosEntrada[posMinimo]->getVecPosTerm(),vecArchsSalida);
	//Libero las posiciones dentro del registro
	vecPosTermMinimo = vectorDeRegistrosEntrada[posMinimo]->getVecPosTerm();
	//delete [] vecPosTermMinimo;
	//vecPosTermMinimo = NULL;
	//libero el recurso;
	delete vectorDeRegistrosEntrada[posMinimo];
	//Me libero la memoria pero no me borra el ptro, entonces la sentencia siguiente;
	vectorDeRegistrosEntrada[posMinimo]=NULL;
}

void NWayMerge::fase1LeerNuevoRegDelArchQueConteniaMinimo(unsigned int posMinimo,unsigned int cantConjProcesados,unsigned int nroDoc,
															std::fstream*& vecArchsEntrada,registroMatrizInicial**& vectorDeRegistrosEntrada){

    char termino[LONG_TERMINO] = "";
    unsigned char largoTermino = 0;
    std::string strTermino;
    unsigned int repeticionesLeidas;
    unsigned int* vecPosTerm = NULL;
    std::string nombArchUsado(NOMBRE_PARTICIONES_SALIDA_MERGE);

    //Ya leí el nroDoc antes de llamar a esta función;
	//Leo largotermino
	vecArchsEntrada[posMinimo].read(reinterpret_cast<char*>(&largoTermino),sizeof(char));
	if(vecArchsEntrada[posMinimo].fail())
		std::cerr<<"[ERROR][MERGE-FASE1-CONJUNTO("<<cantConjProcesados<<")]:Lectura parametro LARGO_TERMINO("<<largoTermino<<") de archivo con reg. minimo."<<std::endl;
	vecArchsEntrada[posMinimo].clear();
	//Leo termino
    vecArchsEntrada[posMinimo].read(termino,largoTermino*sizeof(char));
	if(vecArchsEntrada[posMinimo].fail() )
		std::cerr<<"[ERROR][MERGE-FASE1-CONJUNTO("<<cantConjProcesados<<")]:Lectura parametro TERMINO("<<termino<<") de archivo con reg. minimo."<<std::endl;
	vecArchsEntrada[posMinimo].clear();
	termino[largoTermino] = '\0'; //por las dudas hubo un par que vino sin el '\0' .
	strTermino.assign(termino,largoTermino);
	//Leo repeticiones del termino;
	vecArchsEntrada[posMinimo].read(reinterpret_cast<char*>(&repeticionesLeidas),sizeof(int));
	if(vecArchsEntrada[posMinimo].fail() )
		std::cerr<<"[ERROR][MERGE-FASE1-CONJUNTO("<<cantConjProcesados<<")]:Lectura parametro REPETICIONES("<<termino<<") de archivo con reg. minimo."<<std::endl;
	vecArchsEntrada[posMinimo].clear();
	//Cargar posiciones
	vecPosTerm = new unsigned int[repeticionesLeidas];
	this->fase1cargarPosicionesTermino(posMinimo,repeticionesLeidas,vecPosTerm,nombArchUsado.c_str(),vecArchsEntrada);
	vectorDeRegistrosEntrada[posMinimo] = new registroMatrizInicial(nroDoc,repeticionesLeidas,strTermino,vecPosTerm);
	delete [] vecPosTerm;
}

void NWayMerge::fase1CerrarYLiberarArchSalidaDeEsteConjProcesado(unsigned int cantConjProcesados,std::fstream**& vecArchsSalida){

    if(vecArchsSalida[cantConjProcesados]->is_open()){
        vecArchsSalida[cantConjProcesados]->close();
        delete vecArchsSalida[cantConjProcesados];
    }
}

void NWayMerge::fase1CerrarConjArchRecienProcesados(bool ultimoConjunto,unsigned int cantArchSinProcesar,std::fstream*& vecArchsEntrada){

	unsigned int j;

    if(!ultimoConjunto){
        for(j=0;j<this->raizDeCantArchRepositorio;j++){
            if(vecArchsEntrada[j].is_open())
                vecArchsEntrada[j].close();
        }
    }else{//era el ultimo conjunto
        for(j=0;j<cantArchSinProcesar;j++){
            if(vecArchsEntrada[j].is_open())
                vecArchsEntrada[j].close();
        }
    }
}

void NWayMerge::fase1LiberarRecursosQueNoVoyUsarMas(std::fstream*& vecArchsEntrada,std::fstream**& vecArchsSalida,
													registroMatrizInicial**& vectorDeRegistrosEntrada){

    delete [] vecArchsEntrada;
    delete [] vecArchsSalida;
    delete [] vectorDeRegistrosEntrada;
}

void NWayMerge::fase1NWayMerge(unsigned int cantConj){

    unsigned int cantConjProcesados = 0;
    unsigned int cantArchRepo = this->cantArchAMergear;
    unsigned int cantArchProcesadosEnElConjunto;
    unsigned int cantTotalArchProcesados = 0;
    unsigned int cantArchSinProcesar;
    unsigned int j;
    unsigned int posMinimo;
    std::string terminoMinimoAnterior = TERMINO_MIN_INIC;
    bool termineProcesarArchivos = false;
    bool ultimoConjunto = false;
    registroMatrizInicial** vectorDeRegistrosEntrada;
    std::fstream* vecArchsEntrada;
    std::fstream** vecArchsSalida;
    struct dirent* entry;
    DIR* ruta = opendir(rutaRepositorio);
    char* auxRutaRepo;

    /******************************/
    unsigned int nroDoc;
    //unsigned char largoTermino = 0;
    std::string strTermino;
    /******************************/

    //Inicializo mis variables
    fase1InicializarVectores(vectorDeRegistrosEntrada,vecArchsEntrada,vecArchsSalida);
	//creo (cantConj) archivos de salida con nombre 0_partMerge.dat; 1_partMerge.dat; ... (cantConj-1)_partMerge.dat
	fase1crearParticionesDeSalida(cantConj,vecArchsSalida);
	//Proceso los conjuntos
	rewinddir(ruta);

	while(cantConjProcesados < cantConj){
		//Si es el ultimo conjunto...
		if( (cantConj-cantConjProcesados)==1 ){
			ultimoConjunto = true;
			cantArchSinProcesar = (cantArchRepo - cantTotalArchProcesados);
			//Pongo <= en vez de < porque puede que el ultimo conjunto tenga this->raizDeCantidadArchRepositorio archivos;
			if(cantArchSinProcesar <= this->raizDeCantArchRepositorio){
				//Cargo los faltantes
				for(j=0;j<cantArchSinProcesar;j++){
					entry = readdir(ruta);
					this->fase1PosicionarSoloSobreArchsAMergear(entry,ruta);
					//Obtengo ruta repo
					auxRutaRepo = new char[ANCHO_DIRECTORIO_ARCH_IDX_REPO+1]();
					strncpy(auxRutaRepo,this->rutaRepositorio,strlen(this->rutaRepositorio));
					strcat(auxRutaRepo,entry->d_name);
					vecArchsEntrada[j].open(auxRutaRepo,std::ios_base::binary | std::ios_base::in);
					if(vecArchsEntrada[j].fail())
						std::cerr << "[ERROR][FASE-1]: No se pudo abrir los archivos para procesarlos." << std::endl;
					else{
						this->fase1cargarVecRegsEntrada(j,entry,vecArchsEntrada,vectorDeRegistrosEntrada);
					}
					delete auxRutaRepo;
				}  //fin for j<cantArchSinProcesar
			}//cantArchSinProcesar <= this->raizDeCantArchRepositorio
		}else{//No estoy en el ultimo conjunto
			//cargo this->raizDeCantArchRepositorio archivos de entrada;
			for(j=0;j<this->raizDeCantArchRepositorio;j++){
				entry = readdir(ruta);
				this->fase1PosicionarSoloSobreArchsAMergear(entry,ruta);
				//Obtengo ruta repo
				auxRutaRepo = new char[ANCHO_DIRECTORIO_ARCH_IDX_REPO+1]();
				strncpy(auxRutaRepo,this->rutaRepositorio,strlen(this->rutaRepositorio));
				strcat(auxRutaRepo,entry->d_name);
				vecArchsEntrada[j].open(auxRutaRepo,std::ios_base::binary | std::ios_base::in);
				if(vecArchsEntrada[j].fail())
					std::cerr << "[ERROR][FASE-1]: No se pudo abrir archivo \""<<entry->d_name<<"\" para procesarlo." << std::endl;
				else{
					this->fase1cargarVecRegsEntrada(j,entry,vecArchsEntrada,vectorDeRegistrosEntrada);
				}
				delete auxRutaRepo;
			}//fin del for j<this->raizDeCantArchRepositorio
		}
		cantArchProcesadosEnElConjunto = 0;
		//Proceso este conjunto;
		while(!termineProcesarArchivos){
			posMinimo = obtengoPosicionTermMin(vectorDeRegistrosEntrada);
			this->fase1EscribirMenorEnLaParticionDeSalida(posMinimo,cantConjProcesados,vectorDeRegistrosEntrada,vecArchsSalida);
			if(!vecArchsEntrada[posMinimo].eof()){
				//Leo el registro del archivo que contenía el minimo.
				vecArchsEntrada[posMinimo].read((char*)&nroDoc,sizeof(int));
				if(!vecArchsEntrada[posMinimo].eof()){//realmente no estaba en fin de archivo
					this->fase1LeerNuevoRegDelArchQueConteniaMinimo(posMinimo,cantConjProcesados,nroDoc,vecArchsEntrada,vectorDeRegistrosEntrada);
				}else{
					cantArchProcesadosEnElConjunto++;
					cantTotalArchProcesados++;
				}
			}else{
				cantArchProcesadosEnElConjunto++;
				cantTotalArchProcesados++;
			}
			//Si no estoy procesando el ultimo conjunto
			if(!ultimoConjunto){
				if(cantArchProcesadosEnElConjunto == this->raizDeCantArchRepositorio)
						termineProcesarArchivos = true;
			}else{//ultimo conjunto
				if(cantArchProcesadosEnElConjunto == cantArchSinProcesar)
						termineProcesarArchivos = true;
			}
		}//fin del while(!termineProcesarArchivos)
		termineProcesarArchivos = false;
		//Cierro el archivo de salida usado y libero su memoria.
		this->fase1CerrarYLiberarArchSalidaDeEsteConjProcesado(cantConjProcesados,vecArchsSalida);
		//Cierro el conjunto de archivos recién procesados
		this->fase1CerrarConjArchRecienProcesados(ultimoConjunto,cantArchSinProcesar,vecArchsEntrada);
		cantConjProcesados++;
	} //fin de procesamientoConjuntos
	//Libero recursos que no voy a usar más.
	this->fase1LiberarRecursosQueNoVoyUsarMas(vecArchsEntrada,vecArchsSalida,vectorDeRegistrosEntrada);
	//FIN FASE1
}

/*
 * ******************************************
 * ******************************************
 * 					FASE2
 * ******************************************
 * ******************************************
 */


/* OK */
void NWayMerge::fase2cargarPosicionesTermino(unsigned int j,unsigned int frecTermEnDoc,unsigned int*& vecPosTerm,std::fstream*& vecArchsEntrada){

	unsigned int i = 0;

	do{
		vecArchsEntrada[j].read(reinterpret_cast<char*>(&vecPosTerm[i]),sizeof(unsigned int));
		if(vecArchsEntrada[j].fail())
			std::cerr << "[ERROR][FASE-2][CARGA_POSICIONES]:Lectura parametro: POSICION("<<i<<") de archivos \""<< NOMBRE_PARTICIONES_SALIDA_MERGE << "\"" << std::endl;
		vecArchsEntrada[j].clear();
		i++;
	}while(i < frecTermEnDoc);
}

/* OK */
void NWayMerge::fase2cargarVecRegsEntradaConRegsDeArchQueCree(unsigned int j,std::fstream*& vecArchsEntrada,registroMatrizInicial**& vectorDeRegistrosEntrada){

    unsigned char largoTermino = 0;
    char termino[LONG_TERMINO] = "";
    std::string strTermino;
    unsigned int nroDocLeido,frecTermEnDoc;
    unsigned int* vecPosTerm = NULL;

    vecArchsEntrada[j].read(reinterpret_cast<char*>(&nroDocLeido),sizeof(int) );
    if(vecArchsEntrada[j].fail())
        std::cerr << "[ERROR][FASE-2]: Lectura parametro NRO_DOC(" << nroDocLeido << " archivo \"" << j << NOMBRE_PARTICIONES_SALIDA_MERGE << "\"" << std::endl;
    vecArchsEntrada[j].clear();
    vecArchsEntrada[j].read(reinterpret_cast<char*>(&largoTermino),sizeof(char));
    if(vecArchsEntrada[j].fail())
        std::cerr << "[ERROR][FASE-2]: Lectura parametro LARGO_TERMINO(" << largoTermino << " archivo \"" << j << NOMBRE_PARTICIONES_SALIDA_MERGE << "\"" << std::endl;
    vecArchsEntrada[j].clear();
    vecArchsEntrada[j].read(termino,largoTermino*sizeof(char));
    if(vecArchsEntrada[j].fail())
        std::cerr << "[ERROR][FASE-2]: Lectura parametro TERMINO(" << termino << " archivo \"" << j << NOMBRE_PARTICIONES_SALIDA_MERGE << "\"" << std::endl;
    vecArchsEntrada[j].clear();
    termino[largoTermino] = '\0'; //por las dudas hubo uno que vino sin el '\0' .
    vecArchsEntrada[j].read(reinterpret_cast<char*>(&frecTermEnDoc),sizeof(int));
    if(vecArchsEntrada[j].fail())
        std::cerr << "[ERROR][FASE-2]: Lectura parametro REPETICIONES(" << frecTermEnDoc << " archivo \"" << j << NOMBRE_PARTICIONES_SALIDA_MERGE << "\"" << std::endl;
    vecArchsEntrada[j].clear();
    strTermino.assign(termino,largoTermino);
    //Leo cada posicion y lo almazeno en un vector de posiciones.
	vecPosTerm = new unsigned int[frecTermEnDoc];
	this->fase2cargarPosicionesTermino(j,frecTermEnDoc,vecPosTerm,vecArchsEntrada);
	vectorDeRegistrosEntrada[j] = new registroMatrizInicial(nroDocLeido,frecTermEnDoc,strTermino,vecPosTerm);//constructor de copia
	delete [] vecPosTerm;
}

/* OK */
void NWayMerge::fase2persistirPosicionesTerminoEnArchFinal(unsigned int repeticionesLeidas, unsigned int* vecPosTerm,std::fstream*& fdMatrizInicial){

	unsigned int i;

	for( i = 0; i < repeticionesLeidas; i++){
		fdMatrizInicial->write((char*)&vecPosTerm[i],sizeof(int));
		if(fdMatrizInicial->fail())
			std::cerr<<"[ERROR][MERGE-FASE2][ESCRITURA-ARCH_FINAL]: parametro POSICION["<<i<<"]" << std::endl;
		fdMatrizInicial->clear();

//		if (DEBUG > 1)
//			std::cout << vecPosTerm[i] << " ";
	}
//	if (DEBUG > 1)
//		std::cout << ")";
}

/* OK */
void NWayMerge::fase2PersistirTerminosMinimosIgualesEnArchFinal(unsigned int cantDocsApareceEsteTerm,std::list<registroMatrizInicial> listaDeMismoTerminoMinimo,
																std::fstream*& fdMatrizInicial){
    unsigned char largoTermino = 0;
    std::string strTermino;
    unsigned int nroDocLeido,repeticionesLeidas;
    std::list<registroMatrizInicial>::iterator it = listaDeMismoTerminoMinimo.begin();

    //Escribo la cantidad de docs en los que aparece este termino.
	fdMatrizInicial->write((char*)&cantDocsApareceEsteTerm,sizeof(int));
	if(fdMatrizInicial->fail())
		std::cerr<<"[ERROR][MERGE-FASE2][ESCRITURA-ARCH_FINAL]: parametro CANT_DOCS_TOTAL ("<<cantDocsApareceEsteTerm<<") en " << NOMBRE_ARCH_MAT_INICIAL << std::endl;
	fdMatrizInicial->clear();
	largoTermino = it->getTermino().length();
	//escribo la longitud del minimo;
	fdMatrizInicial->write((char*)&largoTermino,sizeof(char));
	if(fdMatrizInicial->fail())
		std::cerr<<"[ERROR][MERGE-FASE2][ESCRITURA-ARCH_FINAL]: parametro LARGOTERMINO("<<largoTermino<<")" << std::endl;
	fdMatrizInicial->clear();
	//Escribo el termino minimo;
	fdMatrizInicial->write(it->getTermino().c_str(),largoTermino*sizeof(char));
	if(fdMatrizInicial->fail())
		std::cerr<<"[ERROR][MERGE-FASE2][ESCRITURA-ARCH_FINAL]: parametro TERMINO("<<it->getTermino()<<")" << std::endl;
	fdMatrizInicial->clear();

//	if (DEBUG > 1)
//		std::cout<< cantDocsApareceEsteTerm << " " << largoTermino << " " << it->getTermino().c_str() << " " ;

	//Empiezo a escribir la terna <nroDoc-frecEnDoc-posciones>
	for(it = listaDeMismoTerminoMinimo.begin(); it != listaDeMismoTerminoMinimo.end(); it++){
		//Escribo el nro doc;
		nroDocLeido = it->getNroDocumento();
		fdMatrizInicial->write(reinterpret_cast<char*>(&nroDocLeido),sizeof(int));
		if(fdMatrizInicial->fail())
			std::cerr<<"[ERROR][MERGE-FASE2][ESCRITURA-ARCH_FINAL]: parametro NRO_DOC("<<nroDocLeido<<")" << std::endl;
		fdMatrizInicial->clear();
		//Escribo repeticiones del termino;
		repeticionesLeidas = it->getFrecuencia();
		fdMatrizInicial->write(reinterpret_cast<char*>(&repeticionesLeidas),sizeof(int));
		if(fdMatrizInicial->fail())
			std::cerr<<"[ERROR][MERGE-FASE2][ESCRITURA-ARCH_FINAL]: parametro FREC_TERM_EN_DOC("<<repeticionesLeidas<<")" << std::endl;
		fdMatrizInicial->clear();
		//Escribo las posiciones de este termino

//		if (DEBUG > 1)
//			std::cout << "(" << nroDocLeido << ";" << repeticionesLeidas << ";";

		this->fase2persistirPosicionesTerminoEnArchFinal(repeticionesLeidas,it->getVecPosTerm(),fdMatrizInicial);
	}

//	if ( DEBUG > 1)
//		std::cout << "***" << std::endl;
	(this->cantTerminosDistintos)++;
}

void NWayMerge::fase2CargarDatosNuevoRegDeVecArchEntradaEnPosMinimo(unsigned int posMinimo,unsigned int nroDocLeido,std::fstream*& vecArchsEntrada,
																	registroMatrizInicial**& vectorDeRegistrosEntrada){

    char termino[LONG_TERMINO] = "";
    unsigned char largoTermino;
    std::string strTermino;
    unsigned int /*nroDocLeido,*/frecTermEnDoc;
    unsigned int* vecPosTerm = NULL;

	//Leo el largoTermino;
	vecArchsEntrada[posMinimo].read(reinterpret_cast<char*>(&largoTermino),sizeof(char) );
	if(vecArchsEntrada[posMinimo].fail())
		std::cerr << "[ERROR][MERGE-FASE2-POSMINIMO]:Lectura parametro LARGO_TERMINO("<<largoTermino<<") de archivos \""<< NOMBRE_PARTICIONES_SALIDA_MERGE <<"\"."<< std::endl;
	vecArchsEntrada[posMinimo].clear();
	//Leo termino
    vecArchsEntrada[posMinimo].read(termino,largoTermino*sizeof(char));
	if(vecArchsEntrada[posMinimo].fail())
		std::cerr << "[ERROR][MERGE-FASE2-POSMINIMO]:Lectura parametro TERMINO("<<termino<<") de archivos \""<< NOMBRE_PARTICIONES_SALIDA_MERGE <<"\"."<< std::endl;
	vecArchsEntrada[posMinimo].clear();
	termino[largoTermino] = '\0'; //por las dudas hubo un par que vino sin el '\0' .
	strTermino.assign(termino,largoTermino);
	//Leo repeticiones del termino;
	vecArchsEntrada[posMinimo].read(reinterpret_cast<char*>(&frecTermEnDoc),sizeof(int));
	if(vecArchsEntrada[posMinimo].fail())
		std::cerr << "[ERROR][MERGE-FASE2-POSMINIMO]:Lectura parametro: FREC_TERM_EN_DOC("<<frecTermEnDoc<<") de archivos \""<< NOMBRE_PARTICIONES_SALIDA_MERGE <<"\"."<< std::endl;
	vecArchsEntrada[posMinimo].clear();

    //Leo cada posicion y lo almazeno en un vector de posiciones.
	vecPosTerm = new unsigned int[frecTermEnDoc];
	this->fase2cargarPosicionesTermino(posMinimo,frecTermEnDoc,vecPosTerm,vecArchsEntrada);
	vectorDeRegistrosEntrada[posMinimo] = new registroMatrizInicial(nroDocLeido,frecTermEnDoc,strTermino,vecPosTerm);//constructor de copia
	delete [] vecPosTerm;
}


void NWayMerge::fase2CerrarConjArchRecienProcesados(unsigned int cantConj,std::fstream*& vecArchsEntrada){

	unsigned int j;

    for(j=0;j<cantConj;j++){
        if(vecArchsEntrada[j].is_open())
            vecArchsEntrada[j].close();
    }
}

void NWayMerge::fase2CerrarYLiberarArchivoFinal(std::fstream*& fdMatrizInicial){

    if(fdMatrizInicial->is_open()){
        fdMatrizInicial->close();
        delete fdMatrizInicial;
    }
}

void NWayMerge::fase2NWayMerge(unsigned int cantConj){

    unsigned int cantArchProcesadosEnElConjunto;
    unsigned int j;
    unsigned int posMinimo;
    std::string terminoMinimoAnterior = TERMINO_MIN_INIC;
    char representacionDeJ;
    bool termineProcesarArchivos = false;
    registroMatrizInicial** vectorDeRegistrosEntrada;
    std::fstream* vecArchsEntrada;
    std::fstream* fdMatrizInicial = NULL;
//    std::fstream* fdArchTermDistintos = NULL;
    //unsigned int* vecTempPosicionesTermMin = NULL;
    //unsigned char cantTermMinimos = 0;
    //unsigned char largoTermino = 0;
    char termino[LONG_TERMINO] = ""; //NO BORRAR BAJO NINGUN PUNTO DE VISTA!
    std::string strTermino;
    int nroDocLeido,repeticionesLeidas; //NO BORRAR BAJO NINGUN PUNTO DE VISTA!
    /******************************/
    bool esElMismoTerminoMinimo = true;
    unsigned int cantDocsApareceEsteTerm = 0;
    std::string terminoMinimo = "";
    std::string terminoMinimoNuevo = "";
    std::string rutaConNombreArchParticionesMerge(CARPETA_PARTICIONES_MERGE);
    std::list<registroMatrizInicial> listaDeMismoTerminoMinimo;
    std::list<registroMatrizInicial>::iterator it;

    this->fase2inicializarVectores(cantConj,vectorDeRegistrosEntrada,vecArchsEntrada);
    //Creo archivo final "MatrizInicial.dat";
    this->crearArchFinalDelNWayMerge(fdMatrizInicial);
    //this->creoArchConTodosLosTermDistintos(fdArchTermDistintos);
    //Cargo los cantConj archivos que yo cree como salida de la fase1, van a ser las entradas
    if(fdMatrizInicial != NULL){
        termineProcesarArchivos = false;
        for(j=0;j<cantConj;j++){
            itoa(j,&representacionDeJ);
            rutaConNombreArchParticionesMerge.append(&representacionDeJ);//NUEVO
            rutaConNombreArchParticionesMerge.append(NOMBRE_PARTICIONES_SALIDA_MERGE);//NUEVO
            vecArchsEntrada[j].open(rutaConNombreArchParticionesMerge.c_str(),std::ios_base::binary | std::ios_base::in);//lectura
            if(vecArchsEntrada[j].fail() )
            	std::cerr << "[ERROR][FASE-2]: No se pudo abrir \""<< rutaConNombreArchParticionesMerge <<"\" para procesarlo." << std::endl;
            else{
                //Cargo registros de esos archivos;
            	this->fase2cargarVecRegsEntradaConRegsDeArchQueCree(j,vecArchsEntrada,vectorDeRegistrosEntrada);
            }
            rutaConNombreArchParticionesMerge.assign("");
            rutaConNombreArchParticionesMerge.assign(CARPETA_PARTICIONES_MERGE);
        }
        cantArchProcesadosEnElConjunto = 0;
        //Merge de esos archivos al archivo MatrizInicial.dat.
        while(!termineProcesarArchivos){
        	posMinimo = this->fase2obtengoPosicionTermMin(vectorDeRegistrosEntrada);
//			this->contabilizarTerminosDistintos(terminoMinimoAnterior, );
			terminoMinimo.assign(vectorDeRegistrosEntrada[posMinimo]->getTermino());
			cantDocsApareceEsteTerm = 1;
			//Uso una lista con los datos de todos los términos mínimos (#doc,frec,posiciones) pero guardo t_o_d_o el registro;
			while(esElMismoTerminoMinimo && !termineProcesarArchivos){
				//agrego datos del termino minimo
				listaDeMismoTerminoMinimo.push_back(*(vectorDeRegistrosEntrada[posMinimo]) );
				//Leer siguiente de posMinimo;
				if(!vecArchsEntrada[posMinimo].eof()){
					//Leo el siguiente registro del archivo que contenía el minimo.
					vecArchsEntrada[posMinimo].read((char*)&nroDocLeido,sizeof(int));
					if(!vecArchsEntrada[posMinimo].eof()){//realmente no estaba en fin de archivo
						this->fase2CargarDatosNuevoRegDeVecArchEntradaEnPosMinimo(posMinimo,nroDocLeido,vecArchsEntrada,vectorDeRegistrosEntrada);
					}else{
						cantArchProcesadosEnElConjunto++;
						if(vectorDeRegistrosEntrada[posMinimo] != NULL){
							delete vectorDeRegistrosEntrada[posMinimo];
							vectorDeRegistrosEntrada[posMinimo] = NULL;
						}
					}
				}else{
					cantArchProcesadosEnElConjunto++;
					if(vectorDeRegistrosEntrada[posMinimo] != NULL){
						delete vectorDeRegistrosEntrada[posMinimo];
						vectorDeRegistrosEntrada[posMinimo] = NULL;
					}
				}
	            if(cantArchProcesadosEnElConjunto == cantConj)
	                    termineProcesarArchivos = true;
	            else{
					//Obtengo siguiente posMinimo;
					posMinimo = this->fase2obtengoPosicionTermMin(vectorDeRegistrosEntrada);
					terminoMinimoNuevo.assign(vectorDeRegistrosEntrada[posMinimo]->getTermino());
					if (terminoMinimo.compare(terminoMinimoNuevo) )// Si es otro el mínimo...
						esElMismoTerminoMinimo = false;
					else //Sigue siendo el mismo término minimo;
						++cantDocsApareceEsteTerm;
	            }
			}//fin while( esElmismoTerminoMinimo && !termineDeProcesarArchivos)

			//Escribo el menor en el archivo de la matriz.
			this->fase2PersistirTerminosMinimosIgualesEnArchFinal(cantDocsApareceEsteTerm,listaDeMismoTerminoMinimo,fdMatrizInicial);
			//Libero la lista!
			if(listaDeMismoTerminoMinimo.empty() == false)
				listaDeMismoTerminoMinimo.clear();
			//Regenero la condicion de que es el mismo termino ya que es un nuevo termino a ser almacenado
			esElMismoTerminoMinimo = true;
            //Si no estoy procesando el ultimo conjunto
            if(cantArchProcesadosEnElConjunto == cantConj)
                    termineProcesarArchivos = true;
        }//fin while(!termineProcesarArchivos)
        //Cierro el conjunto de archivos recién procesados
        this->fase2CerrarConjArchRecienProcesados(cantConj,vecArchsEntrada);

        // grabo al principio la cantidad de terminos distintos
        fdMatrizInicial->seekg (0, fdMatrizInicial->beg);
        fdMatrizInicial->write(reinterpret_cast<char*>(&(this->cantTerminosDistintos)), sizeof(unsigned long int));

        //Cierro Arch MatrizInicial.dat
        this->fase2CerrarYLiberarArchivoFinal(fdMatrizInicial);
        //Cierro archivo "TerminosDistintos.dat"
        //this->cierroYLiberoArchTermDistintos(fdArchTermDistintos);

    }else{//No se pudo crear el archivo de la matriz inicial.
        std::cerr << "[ERROR]: No se pudo generar el archivo \"" << NOMBRE_ARCH_MAT_INICIAL << "\". " << std::endl;
    }
    //libero recursos
    delete [] vecArchsEntrada;
    delete [] vectorDeRegistrosEntrada;
}

/* OK */
/*Pre-condicion: directorio a ser borrado por "rmdir()" debe estar vacío. */
void NWayMerge::borrarCarpetaMerge(){

	int borradoRealizado;
	std::string carpetaMerge(CARPETA_PARTICIONES_MERGE);

	borradoRealizado = rmdir(carpetaMerge.c_str()); //solo remueve si esta libre!
	if(borradoRealizado == OK){
//		if(DEBUG > 0)
//			std::cout << "Se borro exitosamente \"" << CARPETA_PARTICIONES_MERGE << "\"." << std::endl;
	}
	else
		std::cerr << "[ERROR_ELIMINAR_CARPETA_PARTICIONES_MERGE]: \"" << CARPETA_PARTICIONES_MERGE << "\"." << std::endl;
}

/* OK */
/*Pre-condicion: "remove() necesita la ruta completa para poder borrar el archivo. */
void NWayMerge::borrarParticionesMerge(DIR* dirCarpetaMerge){

	struct dirent* entry;
	std::string nombreArchCompleto(CARPETA_PARTICIONES_MERGE);

	entry = readdir(dirCarpetaMerge);
	while(entry != NULL){
		nombreArchCompleto.append(entry->d_name);
		if(strstr(entry->d_name,NOMBRE_PARTICIONES_SALIDA_MERGE) != NULL){
			if(remove(nombreArchCompleto.c_str()) != OK)
				std::cerr << "[ERROR_ELIMINAR_PARTICIONES_MERGE]: \"" << entry->d_name << "\" no pudo ser eliminado." << std::endl;
		}
		nombreArchCompleto.assign("");
		nombreArchCompleto.assign(CARPETA_PARTICIONES_MERGE);
		entry = readdir(dirCarpetaMerge);
	}
}

/* OK */
/*Pre-condicion: "remove() necesita la ruta completa para poder borrar el archivo. */
void NWayMerge::borrarIndicesUnitarios(DIR* dirCarpetaSalidas){

	struct dirent* entry;
	std::string rutaConNombreArch(CARPETA_ARCHS_A_MERGEAR);

	entry = readdir(dirCarpetaSalidas);
	while(entry != NULL){
		rutaConNombreArch.append(entry->d_name);
		if(strstr(entry->d_name,IDENTIFICADOR_ARCHS_A_MERGEAR) != NULL){
			if(remove(rutaConNombreArch.c_str()) != OK)
				std::cerr << "[ERROR_ELIMINAR_INDICES_UNITARIOS]: \"" << entry->d_name << "\" no pudo ser eliminado." << std::endl;
		}
		rutaConNombreArch.assign("");
		rutaConNombreArch.assign(CARPETA_ARCHS_A_MERGEAR);
		entry = readdir(dirCarpetaSalidas);
	}
}

/* OK */
//Obs. No se utiliza la llamada a system("exec rm -f carpeta/destino/*") para no agregar demasiado overhead al merge desnecesariamente.
void NWayMerge::removeContenidoCarpetaSalidas(){

	DIR* dirCarpetaSalidas;
	DIR* dirCarpetaMerge;
	std::string carpetaSalidas(CARPETA_ARCHS_A_MERGEAR);
	std::string carpetaMerge(CARPETA_PARTICIONES_MERGE);

	dirCarpetaSalidas = opendir(carpetaSalidas.c_str());
	if(dirCarpetaSalidas == NULL){
		std::cerr << "[ERROR_MERGE_ELIMINAR_CONTENIDO_CARPETA]: No se pudo abrir \"" << CARPETA_ARCHS_A_MERGEAR << "\"" << std::endl;
	}else{
		dirCarpetaMerge = opendir(carpetaMerge.c_str());
		if(dirCarpetaMerge == NULL)
			std::cerr << "[ERROR_MERGE_ELIMINAR_CONTENIDO_CARPETA]: No se pudo abrir \"" << CARPETA_PARTICIONES_MERGE << "\"" << std::endl;
		else{
			this->borrarParticionesMerge(dirCarpetaMerge);
			if(closedir(dirCarpetaMerge))
				std::cerr << "[ERROR_CERRAR_DIRECTORIO]: \"" << carpetaMerge << "\"" << std::endl;
			//Borro la carpeta de las particiones del Merge
			this->borrarCarpetaMerge();
		}
		//Borro el contenido de la carpeta "salidas"
		this->borrarIndicesUnitarios(dirCarpetaSalidas);
		if(closedir(dirCarpetaSalidas))
			std::cerr << "[ERROR_CERRAR_DIRECTORIO]: \"" << carpetaSalidas << "\"" << std::endl;
	}
}

/* OK */
int NWayMerge::crearCarpetaParticionesMergeSiNoExiste(std::string strCarpetaParticionesMerge){

    DIR* rutaMergeFiles;
    int status;
    int ejecucionNormal = OK;

    if(DEBUG > 0)
    	std::cout << "Carpeta a crear: " << strCarpetaParticionesMerge << std::endl;
    //Verifico existencia de la carpeta donde voy a guardar _partMerge.dat
    rutaMergeFiles = opendir(strCarpetaParticionesMerge.c_str());
    if(rutaMergeFiles == NULL){ //no existe el directorio
    	//Lo creo como carpeta (1er param);
    	//para lectura,escritura,ejecucion,busqueda por owner (2do param)
    	//para lectura,escritura,ejecucion,busqueda por otros (3er param)
    	status = mkdir(strCarpetaParticionesMerge.c_str(),S_IFDIR | S_IRWXU | S_IRWXO);
    	if (status == 0) {
//    		if(DEBUG > 0)
//    			std::cout << "Carpeta \"" << strCarpetaParticionesMerge << "\" creada. " << std::endl;
    	} else
    		ejecucionNormal = ERROR;
	}
    else
    	closedir(rutaMergeFiles);
    return ejecucionNormal;
}

/* OK */
int NWayMerge::crearCarpetaIndiceFinal(std::string strCarpetaIndiceFinal){

   DIR* rutaIndiceFinal;
	int status;
	int ejecucionNormal = OK;

	//Verifico existencia de la carpeta donde voy a guardar el indice final
	rutaIndiceFinal = opendir(strCarpetaIndiceFinal.c_str());
	if(rutaIndiceFinal == NULL){ //no existe el directorio
		//Lo creo como carpeta (1er param);
		//para lectura,escritura,ejecucion,busqueda por owner (2do param)
		//para lectura,escritura,ejecucion,busqueda por otros (3er param)
		status = mkdir(strCarpetaIndiceFinal.c_str(),S_IFDIR | S_IRWXU | S_IRWXO);
		if (status == 0) {
//			if(DEBUG > 0)
//				std::cout << "Carpeta \"" << strCarpetaIndiceFinal << "\" creada. " << std::endl;
		} else
			ejecucionNormal = ERROR;
	}
	else
		closedir(rutaIndiceFinal);

	return ejecucionNormal;
}

int NWayMerge::crearCarpetasDelMerge(){

    bool creacionExitosaDirConPartionesFase1Merge,creacionExitosaDirIndiceFinal;
    std::string strCarpetaParticionesMerge(CARPETA_PARTICIONES_MERGE);
    //std::string strCarpetaParticionesMerge("./src/IndiceFinal2/"); //a modo de prueba
    std::string strCarpetaIndiceFinal(LSI_DIRECTORY);

    //Crear carpeta Particiones Merge (si no existe).
    creacionExitosaDirConPartionesFase1Merge = this->crearCarpetaParticionesMergeSiNoExiste(strCarpetaParticionesMerge);
    if(creacionExitosaDirConPartionesFase1Merge == ERROR)
    	std::cerr << "[ERROR_CREACION_CARPETA_PARTICIONES_MERGE]: No fue posible crear la carpeta \"" << strCarpetaParticionesMerge << "\"." << std::endl;
    //Crear carpeta IndiceFinal (si no existe).
    creacionExitosaDirIndiceFinal = this->crearCarpetaIndiceFinal(strCarpetaIndiceFinal);
    if(creacionExitosaDirIndiceFinal == ERROR)
    	std::cerr << "[ERROR_CREACION_CARPETA_INDICE_FINAL]: No fue posible crear la carpeta \"" << strCarpetaIndiceFinal << "\"." << std::endl;

    if( (creacionExitosaDirConPartionesFase1Merge == OK) && (creacionExitosaDirIndiceFinal == OK) )
    	return OK;
    else
    	return ERROR;

}

void NWayMerge::mergeDeNVias(){

    unsigned int cantArchRepo = this->contarCantArchivosAMergear();
    unsigned int fase;
    bool apertura_exitosa_dir_a_mergear = true;
    std::string terminoMinimoAnterior = TERMINO_MIN_INIC;
    DIR* ruta = opendir(rutaRepositorio);
    std::string strTermino;

    if(ruta == NULL){
    	std::cerr << "[ERROR_APERTURA_DIR_ARCH_A_MERGEAR]: No se pudo abrir \"" << this->rutaRepositorio << "\"." << std::endl;
    	apertura_exitosa_dir_a_mergear = false;
    }
    if (cantArchRepo > 0) {
        this->raizDeCantArchRepositorio = (unsigned int) ceil(sqrt(cantArchRepo));
        this->cantConj = this->round(cantArchRepo/sqrt(cantArchRepo) );
        //Crear carpeta para particiones Merge y la del IndiceFinal
        if(this->crearCarpetasDelMerge() == OK){
			//Empiezo el merge
			for(fase=1;fase <= CANT_FASES_MERGE;fase++){
				if(fase == 1){
					this->fase1NWayMerge(this->cantConj);
				}else{
					this->fase2NWayMerge(this->cantConj);
				}//fin fase 2
			} //fin for fases
        }
    }else{
    	std::cerr << "[ERROR_CONTAR_DOCS_A_MERGEAR]:\"" << cantArchRepo << "\" archivos a mergear." << std::endl;
    	std::cerr << "Repositorio: " << this->rutaRepositorio << std::endl;
    }
    //Si se pudo abrir el directorio con los archivos entonces,
    if(apertura_exitosa_dir_a_mergear)
    	closedir(ruta);
//    	if(!closedir(ruta) ) {// verifico si no quedó abierto para cerrralo.
//    		std::cout << "Repositorio cerrado correctamente." << std::endl;
//    	}
}


/*Kernighan y Ritchie version of itoa,reverse.*/
/* reverse:  reverse string s in place */
 void NWayMerge::reverse(char s[]) {
     int i, j;
     char c;
 
     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
 }

 /*Kernighan y Ritchie version of itoa,reverse.*/
 /* itoa:  convert n to characters in s */
 void NWayMerge::itoa(int n, char s[]) {
     int i, sign;
 
     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
 }
 
 
/* ****** SETTERS ****** */

void NWayMerge::setDirectorioAMergear(char* directorio){
     
    strcpy(rutaRepositorio,directorio);
}

void NWayMerge::setRaizDeCantArchsAMergear(){
    
    raizDeCantArchRepositorio = (unsigned int) ceil(sqrt(contarCantArchivosAMergear()));
}

unsigned long int NWayMerge::getCantTerminoDistintos(){
    return this->cantTerminosDistintos;
}
